#ifndef LRUCACHE_H
#define LRUCACHE_H
#include <QDebug>
/**
  TinKinG
  2020-8-28
  thread unsafe
*/

#include <list>
#include <unordered_map>

template<typename T,typename Key>
class LRUCache
{
private:
    std::list<Key> m_keys;
    std::unordered_map<Key,T> m_data;
    size_t m_maxCacheCount;
public:
    LRUCache(size_t size = 10)
    {
        m_maxCacheCount = size;
    }

    void setMaxCacheCount(size_t size)
    {
        m_maxCacheCount = size;
    }

    void insert(const Key &key,const T &item)
    {
        auto it = m_data.find(key);
        if (it != m_data.end()) {
            //更新数据;字段提前
            m_data[key] = item;
            moveToHead(key);
            return;
        }

        if (m_maxCacheCount == m_keys.size()) {
            // 达到缓存最值,把老数据删除
            const Key &end = m_keys.back();
            m_data.erase(end);
            m_keys.pop_back();
        }

        m_data[key] = item;
        m_keys.emplace_front(key);
    }

    void remove(const Key &key)
    {
        auto it = m_data.find(key);
        if (it == m_data.end())
            return;

        m_keys.remove(key);
        m_data.erase(it);
    }

    T take(const Key &key)
    {
        if (m_data.find(key) == m_data.end())
            return T();
        return operator [](key);
    }

    const T value(const Key &key, const T &defaultValue = T())
    {
        if (m_data.find(key) != m_data.end())
            return take(key);
        return defaultValue;
    }

    T &operator[](const Key &key)
    {
        try {
            //将此值提前,删除原位置
            moveToHead(key);
            return m_data[key];
        } catch(...) {}
    }

    size_t count()
    {
        return m_maxCacheCount;
    }

    size_t dataCount() const
    {
        return m_data.size();
    }

    void clear()
    {
        m_data.clear();
        m_keys.clear();
    }

    bool contains(const Key &key)
    {
        return m_data.find(key) != m_data.end();
    }

protected:
    void moveToHead(const Key & key)
    {
        auto listIt = std::find(m_keys.begin(),m_keys.end(), key);
        m_keys.emplace_front(*listIt);
        m_keys.erase(listIt);

    }
};

#endif // LRUCACHE_H
